
#pragma once

#include <fmt/format.h>
#include <loguru.hpp>
#include <thread>
#include <string>
#include <vector>
#include <cstdio>
#include <unordered_set>

#ifdef _WIN32
typedef DWORD PID_T;
#else
typedef pid_t PID_T;
#include <unistd.h>
#include <csignal>
#include <dirent.h>
#include <sys/wait.h>
#endif

namespace Util
{

	struct ProcessNode
	{
		PID_T pid;
		std::vector<ProcessNode> children;
		PID_T parent_pid;
		std::string name;
		std::string cmdline;
		explicit ProcessNode(PID_T pid = 0, PID_T ppid = 0, std::string name = "", std::string cmd = "") : pid(pid), parent_pid(ppid), name(name), cmdline(cmd) {}
	};

	/**
	 * note: 该类提供以Windows\Linux的以下代码 importance
	 * 1.获取进程信息
	 * 2.获取进程pid的子孙进程
	 * 3.打印进程pid的进程树
	 * 4.杀死进程
	 * 5.杀死进程及其子孙进程
	 */
	class ProcessUtil
	{
	public:
		/// @brief 拓展popen，调用popen创建子进程执行cmd指令，返回FILE*的同时可以得到子进程的pid
		/// @param cmd 进程执行的指令
		/// @param pidOut pid指针
		/// @return cmd执行成功则返回FILE*指针，失败返回nullptr
		static FILE *PopenEX(const std::string &cmd, PID_T *pidOut = nullptr);

		/// @brief 杀死指定pid的进程
		/// @param pid
		/// @return 成功返回 0
		static int Kill(PID_T pid);

		/// @brief 跨平台system()函数
		/// @param cmd
		/// @return
		static bool Exec(const std::string &cmd);
#ifdef _WIN32
		// 还没实现
#else
		/// @brief 获取进程的ppid和name
		/// @param pid
		/// @param parentPid
		/// @param name
		static void getProcessInfo(pid_t pid, pid_t &parentPid, std::string &name);

		/// @brief 获取进程的cmdline
		/// @param pid
		/// @param cmdline
		static void getProcessCmdline(pid_t pid, std::string &cmdline);

		/// @brief 获取parentPid的所有子进程pid
		/// @param parentPid
		/// @return
		static std::vector<pid_t> getChildPids(pid_t parentPid);
#endif

		/// @brief 递归构造子树入口
		/// @param rootPid 进程pid
		static ProcessNode buildProcessTree(PID_T rootPid);

		static std::string printProcessTree(const ProcessNode &root, bool cmdIsVisable = true);
		// 打印进程树
#ifdef _WIN32
		static std::string printProcessTree(pid_t rootPid = GetCurrentProcessId(), bool cmdIsVisable = true);
#else
		static std::string printProcessTree(pid_t rootPid = getpid(), bool cmdIsVisable = true);
#endif

		/// @brief 杀死进程pid及其子孙进程
		/// @param pid 进程pid
		/// @param isKillSelf 是否杀死pid进程自己
		/// @return 成功返回0
		static int killAllDescendantsProcess(PID_T pid, bool isKillSelf);

		/// @brief 杀死进程pid,并调用waitPid回收子进程
		/// @param pid
		/// @return 成功返回0
		static int killProcess(const ProcessNode &node);

		/// @brief 等待进程终止,同时打印输出日志
		/// @param pid 停止的进程
		/// @return
		static bool waitPid(pid_t pid);

	private:
		/// @brief 递归构造进程树
		/// @param pid
		/// @param node
		/// @param visited
		static void buildTreeRecursive(PID_T pid, ProcessNode &node, std::unordered_set<PID_T> &visited);

		/// @brief 递归获取子孙进程信息
		/// @param node
		/// @param os
		/// @param lastFlags
		/// @param isLast
		/// @param cmdIsVisable
		/// @return 进程信息
		static void printTreeRecursive(const ProcessNode &node, std::ostream &os, const std::vector<bool> &lastFlags,
									   bool isLast, bool cmdIsVisable);
	};
};
